package com.spring.boot;


import com.spring.core.annotation.SpringBootApplication;
import com.spring.core.context.AbstractApplicationContext;
import com.spring.core.context.AnnotationApplicationContext;
import com.spring.core.context.ApplicationContext;
import com.spring.core.factory.AnnotationContextFactory;
import com.spring.embed.EmbedTomcat;

import java.util.*;

/**
 * SpringBoot运行入口类
 * ---------------------------------
 * 1.初始化SpringContext容器
 * 2.扫描配置文件，扫描Bean文件
 * 3.实例化Bean对像
 * 4.执行依赖注入（autowired注入和Value注入）
 * 5.初始化handlerMapping
 * 6.dispatchServlet添加到tomcat
 * 7.启动tomcat服务
 * ----------------------------------
 *
 * @author Zee
 * @version 1.0
 * @date 2021/10/12
 */
public class SpringApplication {
    private Class<?> clazz;

    public SpringApplication(Class<?> clazz) {
        this.clazz = clazz;
    }

    /**
     * springBoot static Run方法
     *
     * @param clazz clazz
     * @return AnnotationApplicationContext
     */
    public static ApplicationContext run(Class<?> clazz, String... args) {
        return new SpringApplication(clazz).run(args);
    }

    /**
     * Spring run方法
     *
     * @return AbstractApplicationContext
     */
    public ApplicationContext run(String... args) {
        //创建容器
        ApplicationContext context = createApplicationContext();
        //处理环境
        prepareEnvironment(args);
        //容器初准备始化
        prepareContext(context);
        //刷新容器
        refreshContext(context);
        //容器刷新后的处理
        afterRefreshContext(context);
        //启动tomcat()
        EmbedTomcat.start(context);
        return context;
    }

    private void prepareEnvironment(String[] args) {
    }

    private void afterRefreshContext(ApplicationContext context) {
        //这里从容器里面获取ApplicationRunner和CommandLineRunner实例的并执行run
        //这里可能会有多个ApplicationRunner 和CommandLineRunner的实现
        List<Object> runners = new ArrayList<>();
        runners.addAll(context.getBeanOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeanOfType(CommandLineRunner.class).values());
        for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner);
            }
        }
    }

    private void callRunner(ApplicationRunner runner) {
        runner.run();
    }

    private void callRunner(CommandLineRunner runner) {
        runner.run();
    }

    private void refreshContext(ApplicationContext context) {
        context.init();
    }

    public ApplicationContext createApplicationContext() {
        //这里还有其它的容器，这里我就只有一个注解类型的容器
        return AnnotationContextFactory.getInstance(this.clazz);
    }

    public void prepareContext(ApplicationContext context) {
        System.out.println("************************");
        System.out.println("*    My Spring Boot    *");
        System.out.println("*            v2.0.0    *");
        System.out.println("************************");
    }

}

